跳到主要内容

App Router和 Page Router

App RouterPages Router 是 Next.js 中两种不同的路由和应用组织方式。简单来说,Pages Router 是旧的、基于文件的简单路由;而 App Router 是新的、基于 React 服务器组件的现代化架构

自 Next.js 13 引入 App Router 后,官方已明确推荐在所有新项目中使用它。

核心区别一览

特性App Router (app 目录)Pages Router (pages 目录)
数据获取React 服务端组件 + fetchgetStaticProps, getServerSideProps
组件类型默认服务端组件,客户端需显式声明 "use client"默认客户端组件
布局 (Layout)原生支持嵌套布局 (layout.js)需手动封装或使用 _app.js
加载/错误内置 loading.jserror.js 文件需手动实现 (如 useRouter().isFallback)
渲染时机SSR 为主,支持静态导出支持 SSG (静态生成) 和 SSR

🔄 数据获取 API 的演变

这是两者最大的不同。App Router 利用 React 服务端组件的能力,让数据获取变得更直观。

1. getStaticProps / getServerSideProps 去哪儿了?

App Router 中,你不再需要 getStaticPropsgetServerSideProps

  • Pages Router 写法 (旧):

    // pages/posts/[id].js
    export async function getServerSideProps(context) {
    const res = await fetch(`https://.../posts/${context.params.id}`);
    const post = await res.json();
    return { props: { post } }; // 传递给页面组件
    }
  • App Router 写法 (新): 你直接在一个异步组件中使用原生 fetch

    // app/posts/[id]/page.js
    // 注意:这是服务端组件,不需要导入 fetch
    export default async function Page({ params }) {
    const res = await fetch(`https://.../posts/${params.id}`, {
    // 在 App Router 中,fetch 的缓存策略更智能
    cache: 'no-store', // 相当于 getServerSideProps (每次都请求)
    // 或 cache: 'force-cache' // 相当于 getStaticProps (静态生成/缓存)
    });
    const post = await res.json();

    return <div>{post.title}</div>;
    }

2. getStaticPaths 去哪儿了?

Pages Router 中,你需要 getStaticPaths 来告诉 Next.js 哪些动态路由需要预渲染。

  • Pages Router 写法 (旧):

    // pages/posts/[id].js
    export async function getStaticPaths() {
    return {
    paths: [{ params: { id: '1' } }, { params: { id: '2' } }],
    fallback: false,
    };
    }
  • App Router 写法 (新): 通常不需要显式定义。当你使用 generateStaticParams 辅助函数时,主要用于生成静态路径(类似 SSG),但这通常用于生成静态站点时。

    // app/posts/[id]/page.js
    export async function generateStaticParams() {
    // 用于生成静态 HTML 的路径
    return [{ id: '1' }, { id: '2' }];
    }

    export default function Page({ params }) {
    // 组件逻辑...
    }

    注意:在 App Router 中,如果未静态生成,访问不存在的动态路由会自动返回 404 或触发 not-found

3. ISR (增量静态再生) 怎么办?

Pages Router 中,你使用 revalidate 选项。

  • Pages Router:

    return { props: {}, revalidate: 60 }; // 60秒重新生成
  • App Router: 通过配置 fetchnext.revalidate 选项来实现:

    const res = await fetch('https://...', {
    next: { revalidate: 60 }, // 60秒重新验证
    });

🛠️ 其他重要 API 和概念变化

Pages Router 概念App Router 对应方案说明
_app.js / _document.jslayout.js / template.jsApp Router 中不需要 _app.js 来共享状态或布局,使用 layout.js 即可。<html><body> 标签移到了根 layout 中。
getInitialProps不推荐 / 中间件用于自定义 _app,在 App Router 中几乎不需要。复杂逻辑推荐使用中间件处理。
加载状态 (Skeleton)loading.js 文件在 Pages Router 中需用 useRouter().isFallback 判断;在 App Router 中,只需在目录下创建 loading.js,框架会自动处理过渡。
错误处理error.js 文件类似 loading.js,创建 error.js 文件即可捕获该路由下的错误边界。

💡 总结与建议

  • 如果你是新项目: 请坚定地使用 App Router

    • 它更符合现代 React 的数据流(Server Components)。
    • 代码更简洁,不需要在 getStaticProps 和组件之间传递 props
    • 布局系统和加载状态管理更强大。
  • 如果你是老项目: 可以继续使用 Pages Router,Next.js 会兼容。但建议逐步学习 App Router,因为它是 Next.js 未来的方向(如 Next.js 15+ 已全面转向 App Router 的最佳实践)。